from market.models import Player
from market.models import Strategy
from market.models import AssetPercentageInStrategy
from market.models import NumberOfAssetsAndMtMPercentageInStrategy
from market.view import View
from market.models import Asset
from market.mathView import vec2view
from market.mathView import view2vec
from market.mathView import viewScalarProduct
from market.marketData import MarketData
from market.math import isARepartition
from market.historyFactory import createHistory

# this class contains all the info on a given player
# this object is the one given to the view that will display it
class PlayerData:

        ###########################################################################################
	# the creation of this object should give all the needed information
	def __init__(self, playerID):
		self.isListedPlayer=True
		# we get the player from the DB
		l = Player.objects.filter(name=playerID)
		#status string for aplying a new repartition
		self.setRepartitionString =""
		# error 
		if len(l) <> 1:
			self.isListedPlayer = False
			return
		# we have he player
		self.dbPlayer = l[0]
		return

        ###########################################################################################
	# return for the player a list of list 
	# [(Asset object, proba that the player gives to that asset)]
	def getViewMainFund(self):
		v = View()
		v.setViewFromStrategy(self.getMainStrategy())
		return v 

        ###########################################################################################
	# this function in case one player will be able to have more than
	# one fund in the future
	def getMainStrategy(self):
		l = Strategy.objects.filter(name=self.dbPlayer.mainStrategy)
		if len(l) <> 1:
			return
		return l[0]

        ###########################################################################################
	# return the name
	def getName(self):
		return self.dbPlayer.name

        ###########################################################################################
        # return the number of specified asset in the fund
	def getNumberOfSpecifiedAssetInMainFund(self, asset):
		return self.getMainFundTotalNumberOfAssets() * self.getViewMainFund().getViewOnAsset(asset)/100

        ###########################################################################################
        # return the number of specified asset in all funds
	def getNumberOfSpecifiedAssetInAllFunds(self, asset):
		n = 0
                for s in self.dbPlayer.numberofassetsandmtmpercentageinstrategy_set.all():
                        v = View()
                        v.setViewFromStrategy( s.strategy )
                        n = n + s.numberOfAssetsInStrategy * v.getViewOnAsset( asset )
                print n
                return n

        ###########################################################################################
	# return the number of assets in the fund
	def getMainFundTotalNumberOfAssets(self):
		strat = self.getMainStrategy()
		s = self.dbPlayer.numberofassetsandmtmpercentageinstrategy_set.filter(strategy = strat)
		if len(s)==1:
			return s[0].numberOfAssetsInStrategy
		return -1


        ###########################################################################################
	# return the mtm of the portfolio (composed of different strategies and number of assets associated to them)
	def getPortfolioMtM(self, marketData):
                mtm = 0
                for s in self.dbPlayer.numberofassetsandmtmpercentageinstrategy_set.all():
                        pv = View()
                        pv.setViewFromStrategy( s.strategy )
                        tmp = s.numberOfAssetsInStrategy
                        mtm = mtm + tmp * marketData.getStrategyMtM( pv )
                return mtm

        ###########################################################################################
	# set the number of asset per strategy using the MtM, the MtM repartition ans the market prices
        def setNumberOfAssetPerStrategy( self, mtm, market ):
                for strat in self.dbPlayer.numberofassetsandmtmpercentageinstrategy_set.all():
                        mtm_stat = strat.mtMPercentageInStrategy * mtm
                        v = View()
                        v.setViewFromStrategy(strat.strategy)
                        mtm_strat_of_1 = market.getStrategyMtM( v )
                        if mtm_strat_of_1 != 0 :
                                strat.numberOfAssetsInStrategy = mtm_stat / ( 100 * mtm_strat_of_1 )
                        else:
                                strat.numberOfAssetsInStrategy = 0
                        strat.save()
                        
                
        ###########################################################################################
        # this the implementation of rule 2 for the changement of strategy from a player. All rules 2 XXX need to call this function ultimatly 
        def setNewView( self, repartition ):
                tmp = isARepartition(repartition)
                #check the repartition
                self.setRepartitionString =""
                if(  tmp[0] == False ):
                        self.setRepartitionString = " " +self.getName() + " wants to submit: ["
                        for i in range(len(repartition)):
                               self.setRepartitionString = self.setRepartitionString + "  %s " %repartition[ i ]
                        self.setRepartitionString = self.setRepartitionString + "] and it is  not a repatition: "+ tmp[1]+ ". Nothing done!"
                        return

                strat = self.getMainStrategy()
                
                m1 = MarketData()
                constantMtM = self.getPortfolioMtM( m1 )
                viewMktBefore = m1.calculateMarketView()
                newView = vec2view(repartition, Asset.objects.all() )
                # first we update proba which already exist
                for prob in strat.assetpercentageinstrategy_set.all():
                        prob.assetPercentageInStrategy = newView.getViewOnAsset( prob.asset )
                        prob.save()
                # then we add the proba on asset which are not yet in the strategy.
                # this allow fo instance to add an asset later on in the data base and change nothing else
                temp = self.getViewMainFund()
                for a in Asset.objects.all():
                        if( newView.getViewOnAsset( a ) != 0 ):
                                if( temp.getViewOnAsset( a ) == 0 ):
                                        # we found a new asset which was not in the previous strategy and therefore need to be added
                                        newProba = AssetPercentageInStrategy(
                                                asset = a,
                                                strategy = strat,
                                                assetPercentageInStrategy = newView.getViewOnAsset( a ) )
                                        newProba.save()
                # computes the new total number of action
                m2 = MarketData()
                self.setNumberOfAssetPerStrategy(constantMtM,m2)
                # create history
                createHistory(m2,strat)
                return

        

        ###########################################################################################
        # set the new strategy mtm repartition.
        # when set the main strat percentage must be greater than 50%
        # this does not hold as the market move, but each time the player change its main strat,
        # the MtM repartition we are definng with this function is set
        def setNewStratMtMRep( self, repartition ):
                names = [ r[0] for r in repartition ]
                rep  = [ r[1] for r in repartition ] 
                # check that the main
                tmp = isARepartition(rep)
                #check the repartition
                self.setRepartitionString =""
                if(  tmp[0] == False ):
                        self.setRepartitionString = " " +self.getName() + " wants to submit: ["
                        for i in range(len(repartition)):
                               self.setRepartitionString = self.setRepartitionString + "  %s " %repartition[ i ]
                        self.setRepartitionString = self.setRepartitionString + "] and it is  not a repatition: "+ tmp[1]+ ". Nothing done!"
                        return
                # check that we have at least 50% on the main strat
                mainStratName = self.getMainStrategy().name
                mainStratFund = False
                for i in range(len(names)):
                        if names[ i ] == mainStratName:
                                mainStratFund = True
                                if rep[ i ] < 50:
                                        self.setRepartitionString = "main strat must have 50 percent of the MtM at least"
                                        return
                if not(mainStratFund):
                        self.setRepartitionString = "main strat must have 50 percent of the MtM at least"
                        return
                        
                # we should now check that the name are actually associated to strategy, but for now, the only function
                # calling this one created the repartition according to strategies names
                # do the job:
                # record the mtm of the portfolio to be able to set the correct number of assets per strategy
                m1 = MarketData()
                constantMtM = self.getPortfolioMtM( m1 )
                for i in range(len(names)):
                        strat = Strategy.objects.filter( name = names[i] )
                        numbAndPerc = self.dbPlayer.numberofassetsandmtmpercentageinstrategy_set.filter( strategy = strat )
                        if len(numbAndPerc) == 1:
                              numbAndPerc[0].mtMPercentageInStrategy = rep[i]
                              numbAndPerc[0].save()
                        if len(numbAndPerc) == 0:
                                newNumAndPerc = NumberOfAssetsAndMtMPercentageInStrategy(
                                        strategy = strat,
                                        player = self.dbPlayer,
                                        numberOfAssetsInStrategy = 0,#dummy, will be set in 2 lines
                                        mtMPercentageInStrategy = rep[i] )
                                newNumAndPerc.save()
                        # else :  not possible since the strategy names are unique
                self.setNumberOfAssetPerStrategy( constantMtM, m1 )
                return
                
                
                


